package net.bither.util;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class NativeUtil {

	private static int DEFAULT_QUALITY = 95;

	/**
	 * 1.JNI终极压缩（通过JNI图片压缩把Bitmap保存到指定目录）
	 *
	 * @param image    bitmap对象
	 * @param filePath 要保存的指定目录
	 * @Description: 通过JNI图片压缩把Bitmap保存到指定目录
	 */
	public static void jniUltimateCompress(Bitmap image, String filePath) {
		// 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
		int quality = 20;
		// JNI调用保存图片到SD卡 这个关键
		NativeUtil.saveBitmap (image, quality, filePath, true);
	}

	/**
	 * 1.JNI基本压缩（不保存Bitmap）
	 *
	 * @param bit      bitmap对象
	 * @param fileName 指定保存目录名
	 * @param optimize 是否采用哈弗曼表数据计算 品质相差5-10倍
	 * @Description: JNI基本压缩
	 */
	public static void jniBasicCompress(Bitmap bit, String fileName, boolean optimize) {
		saveBitmap (bit, DEFAULT_QUALITY, fileName, optimize);
	}

	/**
	 * 2.混合终极方法（尺寸、质量、JNI压缩）
	 *
	 * @param image    bitmap对象
	 * @param filePath 要保存的指定目录
	 * @Description: 通过JNI图片压缩把Bitmap保存到指定目录
	 */
	public static boolean mixCompress(Bitmap image, String filePath) {
		// 最大图片大小 1000KB
		int maxSize = 200;
		// 获取尺寸压缩倍数
		int ratio = NativeUtil.getRatioSize (image.getWidth (), image.getHeight ());
		// 压缩Bitmap到对应尺寸
		Bitmap result = Bitmap.createBitmap (image.getWidth () / ratio, image.getHeight () / ratio, Config.ARGB_8888);
		Canvas canvas = new Canvas (result);
		Rect rect = new Rect (0, 0, image.getWidth () / ratio, image.getHeight () / ratio);
		canvas.drawBitmap (image, null, rect, null);

		ByteArrayOutputStream baos = new ByteArrayOutputStream ();
		// 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
		int quality = 100;
		result.compress (Bitmap.CompressFormat.JPEG, quality, baos);
		// 循环判断如果压缩后图片是否大于最大值,大于继续压缩
		try {
			//baos.toByteArray() 有可能导致 OOM
			while (baos.toByteArray ().length / 1024 > maxSize) {
				// 重置baos即清空baos
				baos.reset ();
				// 每次都减少10
				quality -= 10;
				// 这里压缩options%，把压缩后的数据存放到baos中
				result.compress (Bitmap.CompressFormat.JPEG, quality, baos);
			}
			// JNI调用保存图片到SD卡 这个关键
			NativeUtil.saveBitmap (result, quality, filePath, true);
			// 释放Bitmap
			if (result != null && ! result.isRecycled ()) {
				result.recycle ();
				result = null;
			}
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	public static boolean mixCompress(String sourseFile, String saveToLocalFile) {
		// 最大图片大小 500KB
		int maxSize = 200;
		Bitmap result = getBitmapFromFile (sourseFile);
		if(result==null){
			return false;
		}
		ByteArrayOutputStream baos = new ByteArrayOutputStream ();
		// 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
		int quality = 100;
		result.compress (Bitmap.CompressFormat.JPEG, quality, baos);
		// 循环判断如果压缩后图片是否大于最大值,大于继续压缩
		try {
			//baos.toByteArray() 有可能导致 OOM
			while (baos.toByteArray ().length / 1024 > maxSize) {
				// 重置baos即清空baos
				baos.reset ();
				// 每次都减少10
				quality -= 10;
				// 这里压缩options%，把压缩后的数据存放到baos中
				result.compress (Bitmap.CompressFormat.JPEG, quality, baos);
			}
			// JNI调用保存图片到SD卡 这个关键
			NativeUtil.saveBitmap (result, quality, saveToLocalFile, true);
			// 释放Bitmap
			if ( ! result.isRecycled ()) {
				result.recycle ();
				result = null;
			}
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 计算缩放比
	 *
	 * @param bitWidth  当前图片宽度
	 * @param bitHeight 当前图片高度
	 * @return
	 * @Description:函数描述
	 */
	public static int getRatioSize(int bitWidth, int bitHeight) {
		// 图片最大分辨率
		int imageHeight = 1920;
		int imageWidth = 1080;
		// 缩放比
		int ratio = 1;
		// 缩放比,由于是固定比例缩放，只用高或者宽其中一个数据进行计算即可
		if (bitWidth > bitHeight && bitWidth > imageHeight) {
			// 如果图片宽度比高度大,以宽度为基准
			ratio = bitWidth / imageHeight;
		} else if (bitWidth < bitHeight && bitHeight > imageHeight) {
			// 如果图片高度比宽度大，以高度为基准
			ratio = bitHeight / imageHeight;
		}
		// 最小比率为1
		if (ratio <= 0)
			ratio = 1;
		return ratio;
	}

	/**
	 * 调用native方法
	 *
	 * @param bit
	 * @param quality
	 * @param fileName
	 * @param optimize
	 * @Description:函数描述
	 */
	private static void saveBitmap(Bitmap bit, int quality, String fileName, boolean optimize) {
		compressBitmap (bit, bit.getWidth (), bit.getHeight (), quality, fileName.getBytes (), optimize);
	}

	/**
	 * 调用底层 bitherlibjni.c中的方法
	 *
	 * @param bit
	 * @param w
	 * @param h
	 * @param quality
	 * @param fileNameBytes
	 * @param optimize
	 * @return
	 * @Description:函数描述
	 */
	private static native String compressBitmap(Bitmap bit, int w, int h, int quality, byte[] fileNameBytes,
			boolean optimize);

	/**
	 * 加载lib下两个so文件
	 */
	static {
		System.loadLibrary ("jpegbither");
		System.loadLibrary ("bitherjni");
	}

	/**
	 * 3.质量压缩
	 * 设置bitmap options属性，降低图片的质量，像素不会减少
	 * 第一个参数为需要压缩的bitmap图片对象，第二个参数为压缩后图片保存的位置
	 * 设置options 属性0-100，来实现压缩
	 *
	 * @param bmp
	 * @param file
	 */
	public static void qualityCompress(Bitmap bmp, File file) {
		// 0-100 100为不压缩
		int quality = 20;
		ByteArrayOutputStream baos = new ByteArrayOutputStream ();
		// 把压缩后的数据存放到baos中
		bmp.compress (Bitmap.CompressFormat.JPEG, quality, baos);
		try {
			FileOutputStream fos = new FileOutputStream (file);
			fos.write (baos.toByteArray ());
			fos.flush ();
			fos.close ();
		} catch (Exception e) {
			e.printStackTrace ();
		}
	}

	/**
	 * 4.尺寸压缩（通过缩放图片像素来减少图片占用内存大小）
	 *
	 * @param bmp
	 * @param file
	 */

	public static void sizeCompress(Bitmap bmp, File file) {
		// 尺寸压缩倍数,值越大，图片尺寸越小
		int ratio = 8;
		// 压缩Bitmap到对应尺寸
		Bitmap result = Bitmap.createBitmap (bmp.getWidth () / ratio, bmp.getHeight () / ratio, Config.ARGB_8888);
		Canvas canvas = new Canvas (result);
		Rect rect = new Rect (0, 0, bmp.getWidth () / ratio, bmp.getHeight () / ratio);
		canvas.drawBitmap (bmp, null, rect, null);

		ByteArrayOutputStream baos = new ByteArrayOutputStream ();
		// 把压缩后的数据存放到baos中
		result.compress (Bitmap.CompressFormat.JPEG, 100, baos);
		try {
			FileOutputStream fos = new FileOutputStream (file);
			fos.write (baos.toByteArray ());
			fos.flush ();
			fos.close ();
		} catch (Exception e) {
			e.printStackTrace ();
		}
	}


	/**
	 * 5.采样率压缩（设置图片的采样率，降低图片像素）
	 *
	 * @param filePath
	 * @param file
	 */
	public static void samplingRateCompress(String filePath, File file) {
		// 数值越高，图片像素越低
		int inSampleSize = 8;
		BitmapFactory.Options options = new BitmapFactory.Options ();
		options.inJustDecodeBounds = false;
//	        options.inJustDecodeBounds = true;//为true的时候不会真正加载图片，而是得到图片的宽高信息。
		//采样率
		options.inSampleSize = inSampleSize;
		Bitmap bitmap = BitmapFactory.decodeFile (filePath, options);

		ByteArrayOutputStream baos = new ByteArrayOutputStream ();
		// 把压缩后的数据存放到baos中
		bitmap.compress (Bitmap.CompressFormat.JPEG, 100, baos);
		try {
			if (file.exists ()) {
				file.delete ();
			} else {
				file.createNewFile ();
			}
			FileOutputStream fos = new FileOutputStream (file);
			fos.write (baos.toByteArray ());
			fos.flush ();
			fos.close ();
		} catch (Exception e) {
			e.printStackTrace ();
		}
	}


	/**
	 * 通过文件路径读获取Bitmap防止OOM以及解决图片旋转问题
	 *
	 * @param filePath
	 * @return
	 */

	public static Bitmap getBitmapFromFile(String filePath) {

		BitmapFactory.Options newOpts = new BitmapFactory.Options ();
		newOpts.inJustDecodeBounds = true;//只读边,不读内容
		BitmapFactory.decodeFile (filePath, newOpts);
		int w = newOpts.outWidth;
		int h = newOpts.outHeight;
		// 获取尺寸压缩倍数
		newOpts.inSampleSize = NativeUtil.getRatioSize (w, h);
		newOpts.inJustDecodeBounds = false;//读取所有内容
		newOpts.inDither = false;
		newOpts.inPurgeable = true;
		newOpts.inInputShareable = true;
		newOpts.inTempStorage = new byte[32 * 1024];
		Bitmap bitmap = null;
		File file = new File (filePath);
		FileInputStream fs = null;
		try {
			fs = new FileInputStream (file);
		} catch (FileNotFoundException e) {
			e.printStackTrace ();
		}
		try {
			if (fs != null) {
				bitmap = BitmapFactory.decodeFileDescriptor (fs.getFD (), null, newOpts);
			}
		} catch (IOException e) {
			e.printStackTrace ();
		} finally {
			if (fs != null) {
				try {
					fs.close ();
				} catch (IOException e) {
					e.printStackTrace ();
				}
			}
		}
		return bitmap;

	}
}
